﻿#region using 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using DanielsGameLibrary;
using DanielsGameLibrary.Input;
using ParticalEngin;
#endregion

public class Pointlight
{
    
    public Vector3  Position;
    public Color    color;

    public Pointlight(Vector3 p, Color c) {
        Position = p;
        color = c;
    }
}

public class GameObject: Movable
{
    public Model model { get; set; }

    public BoundingSphere BoundingSphere { get; set; }

     float shininess = 2f;
     float specularPower = 1f;
    

    public GameObject()
    {
           
        Position = Vector3.Zero;
        Orientation = Vector3.Zero;
        BoundingSphere = new BoundingSphere();
        
    }

    public override BoundingBox getAABB()
    {
        Matrix[] transforms = new Matrix[model.Bones.Count];
        model.CopyAbsoluteBoneTransformsTo(transforms);

        Dictionary<string, object> data = (Dictionary<string, object>)model.Tag;
        BoundingBox volume = ((List<BoundingBox>)data["BoundingBoxs"])[0];

        return new BoundingBox(Vector3.Transform(volume.Min, Matrix.Identity * Matrix.CreateTranslation(Vector3.Transform(Position, transforms[1]))),
                               Vector3.Transform(volume.Max, Matrix.Identity * Matrix.CreateTranslation(Vector3.Transform(Position, transforms[1]))));
    }

    

    public GameObject(Vector3 p, Vector3 o, Vector3 force)
    {
        model = null;
        Position = p;
        Orientation = o;
        BoundingSphere = new BoundingSphere();
    }

    public virtual void LoadContent(ContentManager content, string modelName)
    {
        
        
        model = content.Load<Model>(modelName);
        foreach (ModelMesh mesh in model.Meshes)
        {
            foreach (Effect effect in mesh.Effects)
            {
                
                   

                    effect.Parameters["Shininess"].SetValue(shininess);
                    effect.Parameters["SpecularPower"].SetValue(specularPower);
                    

    
                    effect.Parameters["AmbientLightColor"].SetValue(new Vector4(0.075f, 0.075f, 0.077f, .5f));
                    effect.Parameters["AmbientIntensity"].SetValue(3.0f);


                    

                    

                    

                    effect.Parameters["pointLightPosition"].SetValue( new Vector3(200, 200, 200));

                    

                    effect.Parameters["pointLightColorIntensity"].SetValue(new Vector4(1, 1f, 1f, 0.99f));
                    
                    //effect.Parameters["CelMap"].SetValue(GameConstants.Toon);
                
            }
        }


        
    }

    void RenderMesh(GraphicsDevice device, ModelMesh mesh)
    {
        
        

        foreach (ModelMeshPart part in mesh.MeshParts)
        {
           
            if (part.NumVertices > 0)
            {
                device.Indices = part.IndexBuffer;

                device.SetVertexBuffer( part.VertexBuffer, part.VertexOffset);
                device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, part.NumVertices, part.StartIndex, part.PrimitiveCount);
            }
        }
    }

    public virtual void Draw(Camera cam, bool enablecliping, Vector4 clipingplane, GraphicsDevice GDevice)
    {

        

        Matrix[] transforms = new Matrix[model.Bones.Count];
        model.CopyAbsoluteBoneTransformsTo(transforms);

        DepthStencilState depthState = new DepthStencilState();
        depthState.DepthBufferEnable = true; /* Enable the depth buffer */
        depthState.DepthBufferWriteEnable = true; /* When drawing to the screen, write to the depth buffer */
        GDevice.DepthStencilState = depthState;
        
        Matrix worldMatrix = Matrix.Identity;
        worldMatrix *= Matrix.CreateTranslation(Position);
        worldMatrix *= Matrix.CreateRotationZ(Orientation.Z);
        worldMatrix *= Matrix.CreateRotationY(Orientation.Y);
        worldMatrix *= Matrix.CreateRotationX(Orientation.X);

        
        foreach (ModelMesh mesh in model.Meshes)
        {
            
            foreach (Effect currentEffect in mesh.Effects)
            {
                currentEffect.Parameters["View"].SetValue(cam.ViewMatrix);
                currentEffect.Parameters["Projection"].SetValue(cam.ProjectionMatrix);
                currentEffect.Parameters["World"].SetValue(worldMatrix * transforms[mesh.ParentBone.Index]);


                currentEffect.Parameters["pointLightPosition"].SetValue(new Vector3(800, 200, 800));
                currentEffect.Parameters["pointLightColorIntensity"].SetValue(new Vector4(1, 1f, 1f, 0.99f));
                currentEffect.CurrentTechnique.Passes[1].Apply();
                RenderMesh(GDevice, mesh);

                

                

            }
            
        }
    }
}

class Barrier : GameObject
{
    public string BarrierType { get; set; }
        

    public Barrier()
        : base()
    {
        BarrierType = null;
            
    }

}

public class Bomb : GameObject
{
    float countdown = 3f;
    bool dead = false;

    ParticleSystem explosionParticles;
    ParticleSystem explosionSmokeParticles;
    ParticleEmitter trailEmitter;

    const float trailParticlesPerSecond = 200;

    float age;

    public Bomb(Vector3 p, float time, ContentManager content, Vector3 f, Vector3 t, 
                ParticleSystem explosionParticles,
                ParticleSystem explosionSmokeParticles,
                ParticleSystem projectileTrailParticles)
        : base()
    {
        this.explosionParticles = explosionParticles;
        this.explosionSmokeParticles = explosionSmokeParticles;

        LoadContent(content, @"Models\bomb");
        Matrix[] transforms = new Matrix[model.Bones.Count];
        model.CopyAbsoluteBoneTransformsTo(transforms);
        Position =p;
        countdown = time;
        Force += f;
        Torque += t;

        trailEmitter = new ParticleEmitter(projectileTrailParticles,
                                           trailParticlesPerSecond, Position);
        
    }

    public void Update(GameTime gameTime)
    {
        float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
        
        countdown -= dt;
        momentOfInertia = 0.99f;
        Move(dt);
        //trailEmitter.Update(gameTime, Position);
    }

    public override BoundingBox getAABB()
    {
        Matrix[] transforms = new Matrix[model.Bones.Count];
        model.CopyAbsoluteBoneTransformsTo(transforms);

        Dictionary<string, object> data = (Dictionary<string, object>)model.Tag;
        BoundingBox volume = ((List<BoundingBox>)data["BoundingBoxs"])[0];

        Matrix worldMatrix = Matrix.Identity;
        worldMatrix *= Matrix.CreateTranslation(Position);
        
        return new BoundingBox(Vector3.Transform(volume.Min, worldMatrix),
                               Vector3.Transform(volume.Max, worldMatrix));
    }

    public override void Draw(Camera cam, bool enablecliping, Vector4 clipingplane, GraphicsDevice device)
    {
        Matrix[] transforms = new Matrix[model.Bones.Count];
        model.CopyAbsoluteBoneTransformsTo(transforms);

        device.BlendState = BlendState.NonPremultiplied;
        
        Matrix worldMatrix = Matrix.Identity;
        
        worldMatrix *= Matrix.CreateRotationZ(Orientation.Z);
        worldMatrix *= Matrix.CreateRotationY(Orientation.Y);
        worldMatrix *= Matrix.CreateRotationX(Orientation.X);
        worldMatrix *= Matrix.CreateTranslation(Vector3.Transform(Position, Matrix.Invert(transforms[1])));

        
        foreach (ModelMesh mesh in model.Meshes)
        {
            foreach (Effect currentEffect in mesh.Effects)
            {
                currentEffect.Parameters["View"].SetValue(cam.ViewMatrix);
                currentEffect.Parameters["Projection"].SetValue(cam.ProjectionMatrix);
                currentEffect.Parameters["World"].SetValue(worldMatrix * transforms[mesh.ParentBone.Index]);

            }
            mesh.Draw();
        }
    }
    
}

public class Hero : Movable
{
    private Vector2 center;

    public Hero(Vector2 cent, Vector3 p)
    {
        center = cent;
        Mouse.SetPosition((int)center.X, (int)center.Y);
        Position = p;
    }

    public void Update(GameTime gameTime, Game1 game, ContentManager content, 
                       ParticleSystem explosionParticles,
                       ParticleSystem explosionSmokeParticles,
                       ParticleSystem projectileTrailParticles)
    {
        float dtm = gameTime.ElapsedGameTime.Milliseconds;

        Torque.X = MathHelper.ToRadians((CMouse.Y - center.Y)) * 10; // pitch
        Torque.Y = MathHelper.ToRadians((CMouse.X - center.X)) * 10; // yaw


        if (CKeyBoard.Up.Hold && contact)

            Force.Z += -2000;

        if (CKeyBoard.Down.Hold && contact)
            Force.Z += 2000;

        if (CKeyBoard.Left.Hold && contact)
            Force.X += -700;

        if (CKeyBoard.Right.Hold && contact)
            Force.X += 700;

        if (CKeyBoard.PageDown.Hold)
            Force.Y += -1000;

        if (CKeyBoard.PageUp.Hold)
            Force.Y += 1000;
        if (CKeyBoard.Space.Pressed && contact)
        {
            Position.Y += 10;
            Force.Y += 40000;
        }

        if(CKeyBoard.K.Pressed){
            Matrix rotationMatrix = Matrix.CreateRotationY(-Orientation.Y);
            Vector3 frc = Vector3.Transform((Vector3.UnitZ * -30000) + (Vector3.UnitY*10000), rotationMatrix);
            game.bombs.Add(new Bomb(Position, 3f, content,frc,new Vector3(390, 390,0),
                           explosionParticles, explosionSmokeParticles, projectileTrailParticles));
        }
        

        Move(dtm);
    }
}

class SkyDome : GameObject
{
    Texture2D cloudMap;
    RenderTarget2D cloudsRenderTarget;
    Texture2D cloudStaticMap;
    PerlinNoiseGenerater cloudRender;
    Vector2 windspeed;
    float OverCast;


    public SkyDome(GraphicsDevice divice,Vector2 wspeed, float overcast)
    {
        cloudRender = new PerlinNoiseGenerater(divice, 32);
        windspeed = wspeed;
        OverCast = overcast;
    }

    public SkyDome(GraphicsDevice divice, ContentManager content, string modelName, Effect setEffect, Vector2 wspeed, float overcast)
    {
        cloudRender = new PerlinNoiseGenerater(divice, 32);
        LoadContent(content, modelName, setEffect);
        windspeed = wspeed;
        OverCast = overcast;
    }

    public void LoadContent(ContentManager content, string modelName, Effect setEffect)
    {
        model = content.Load<Model>(modelName);
        model.Meshes[0].MeshParts[0].Effect = setEffect.Clone();
    }

    public void Draw(Camera cam, GraphicsDevice GDevice, float time)
    {
        cloudMap = cloudRender.GeneratePerlinNoise(GDevice, GameConstants.DefaultEffect, time, windspeed, OverCast);

        DepthStencilState depthState = new DepthStencilState();
        depthState.DepthBufferEnable = false; /* Enable the depth buffer */
        depthState.DepthBufferWriteEnable = false; /* When drawing to the screen, write to the depth buffer */
        GDevice.DepthStencilState = depthState;

        GDevice.BlendState = BlendState.Opaque; 
        


        Matrix[] modelTransforms = new Matrix[model.Bones.Count];

        model.CopyAbsoluteBoneTransformsTo(modelTransforms);

        Matrix wMatrix = Matrix.CreateTranslation(0, -0.3f, 0) * Matrix.CreateScale(100) * Matrix.CreateTranslation(cam.position);
        foreach (ModelMesh mesh in model.Meshes)
        {
            foreach (Effect currentEffect in mesh.Effects)
            {
                Matrix worldMatrix = modelTransforms[mesh.ParentBone.Index] * wMatrix;
                currentEffect.CurrentTechnique = currentEffect.Techniques["SkyDome"];
                currentEffect.Parameters["xWorld"].SetValue(worldMatrix);
                currentEffect.Parameters["xView"].SetValue(cam.ViewMatrix);
                currentEffect.Parameters["xProjection"].SetValue(cam.ProjectionMatrix);
                currentEffect.Parameters["xTexture0"].SetValue(cloudMap);
                currentEffect.Parameters["xEnableLighting"].SetValue(false);

            }
            mesh.Draw();
        }
        depthState = new DepthStencilState();
        depthState.DepthBufferEnable = true; /* Enable the depth buffer */
        depthState.DepthBufferWriteEnable = true; /* When drawing to the screen, write to the depth buffer */
        GDevice.DepthStencilState = depthState;
    }

}